package com.googlecode.monitoring.db.dao;

import com.googlecode.monitoring.dao.AgentConfigurationDao;
import com.googlecode.monitoring.dao.XmlUtils;
import com.googlecode.monitoring.db.model.DataSourceItem;
import com.googlecode.monitoring.db.model.DbItemToCheck;
import com.googlecode.monitoring.exception.DataDaoException;
import com.googlecode.monitoring.model.AlertText;
import com.googlecode.monitoring.model.ItemToCheck;
import com.googlecode.monitoring.model.Person;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Repository;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Author: Sergiy Doroshenko
 * Date: May 17, 2010
 * Time: 12:22:34 PM
 */
@Repository
public class XmlDbAgentConfigurationDao extends AgentConfigurationDao {

    Logger log = Logger.getLogger(XmlDbAgentConfigurationDao.class);

    private Resource xmlDbConfigResource;
    private Map<String, DataSourceItem> dataSourceItems;
    private List<Person> commonResponsiblePersonList;

    private XmlUtils xmlUtils;
    private DbAgentXmlUtils dbAgentXmlUtils = new DbAgentXmlUtils();

    @Autowired
    public void setXmlUtils(XmlUtils xmlUtils) {
        this.xmlUtils = xmlUtils;
    }

    public Resource getXmlDbConfigResource() {
        return xmlDbConfigResource;
    }

    @Autowired
    public void setXmlDbConfigResource(Resource xmlDbConfigResource) {
        this.xmlDbConfigResource = xmlDbConfigResource;
    }

    @Override
    public List<ItemToCheck> getAllItemsFromConfiguration() throws DataDaoException {
        return getXmlDataItemsFromConfig();
    }
    
    @Override
    public List<Person> getCommonResponsiblePersons() throws DataDaoException {
        if (commonResponsiblePersonList == null) {
            commonResponsiblePersonList = new ArrayList<Person>();
            try {
                Document doc = xmlUtils.getDocumentFromResource(xmlDbConfigResource, true);
                Element alertsElem = (Element) doc.getElementsByTagName("alerts").item(0);
                NodeList personNodes = alertsElem.getElementsByTagName("person");
                commonResponsiblePersonList.addAll(xmlUtils.buildPersons(personNodes));
            } catch (Throwable e) {
                log.error(e);
                throw new DataDaoException(e);
            }
        }
        return commonResponsiblePersonList;
    }

    public Map<String, DataSourceItem> getDataSourceItemMap() throws DataDaoException {
        if (dataSourceItems == null) {
            dataSourceItems = new HashMap<String, DataSourceItem>();
            try {
                XPath xpath = XPathFactory.newInstance().newXPath();
                Document doc = xmlUtils.getDocumentFromResource(xmlDbConfigResource, true);
                XPathExpression exprChildOfItem = xpath.compile("document/datasource");
                NodeList datasourceNodes = (NodeList) exprChildOfItem.evaluate(doc, XPathConstants.NODESET);
                for (int i = 0; i < datasourceNodes.getLength(); i++) {
                    Node node = datasourceNodes.item(i);
                    DataSourceItem dataSourceItem = dbAgentXmlUtils.buildDataSourceItemFromNode(node);
                    dataSourceItems.put(dataSourceItem.getId(), dataSourceItem);
                }
            } catch (Throwable e) {
                log.error(e);
                throw new DataDaoException(e);
            }
        }
        return dataSourceItems;
    }

    /**
     * reading xml document and build AlertText object from xml node
     *
     * @return AlertText
     * @throws DataDaoException
     */
    @Override
    public AlertText getAlertText() throws

            DataDaoException {
        try {
            Document doc = xmlUtils.getDocumentFromResource(xmlDbConfigResource, false);
            return xmlUtils.getAlertText(doc);
        } catch (Throwable e) {
            log.error(e);
            throw new DataDaoException(e);
        }
    }

    private List<ItemToCheck> getXmlDataItemsFromConfig() throws DataDaoException {
        try {
            Document doc = xmlUtils.getDocumentFromResource(xmlDbConfigResource, true);
            NodeList nodes = doc.getElementsByTagName("item");
            List<ItemToCheck> items = new ArrayList<ItemToCheck>(nodes.getLength());
            log.debug("readed " + nodes.getLength() + " nodes item");
            for (int i = 0; i < nodes.getLength(); i++) {
                Node xmlItem = nodes.item(i);
                if (xmlItem.getNodeType() == Node.ELEMENT_NODE) {
                    try {
                        items.add(dbAgentXmlUtils.buildDataToCheck((Element) xmlItem,getDataSourceItemMap()));
                    } catch (Exception e) {
                        log.error(xmlItem.toString() + ";i=" + i, e);
                        throw new DataDaoException(xmlItem.toString(), e);
                    }
                }
            }
            return items;
        } catch (Throwable e) {
            throw new DataDaoException(e);
        }
    }

    
    public String replacePlaseHoldersInAlertText(Person person, ItemToCheck item, String text) throws DataDaoException {
        try {
            DbItemToCheck dbItemToCheck = (DbItemToCheck) item;
            Document doc = xmlUtils.getDocumentFromResource(xmlDbConfigResource, true);
            XPath xpath = XPathFactory.newInstance().newXPath();
            List<String[]> placeHolders = xmlUtils.getPlaceHolders(text);
            for (String[] p : placeHolders) {
                if (p[0].equals("person")) {
                     text = xmlUtils.replacePlaceHoldersInPerson(person, text, doc, p[1]);
                } else if (p[0].equals("item")) {
                    text = xmlUtils.replacePlaceHoldersInItem(item, text, doc, p);
                } else if (p[0].equals("datasource")) {
                    XPathExpression expr = xpath.compile("document/datasource[@id='" + dbItemToCheck.getDataSourceItem().getId() + "']"); // get any child of item node
                    Object result = expr.evaluate(doc, XPathConstants.NODE);
                    Node node = (Node) result;
                    expr = xpath.compile("attribute::" + p[1]);
                    result = expr.evaluate(node, XPathConstants.STRING);
                    text = text.replaceAll("\\{datasource\\." + p[1] + "}", result.toString());
                }
            }

        } catch (Throwable e) {
            throw new DataDaoException(e);
        }
        return text;
    }


}
